# = StarFrame::Sprite::Collision -- スプライト当たり判定定義
require "starframe/sprite/collision/dot"
require "starframe/sprite/collision/circle"
require "starframe/sprite/collision/rect"

module StarFrame
  class Sprite
    # = Sprite::Collisionクラス
    # スプライト当たり判定クラス。
    # 
    # 衝突判定を行い、適切な衝突処理を実行するクラス。
    class Collision
      class << self
        def dot_in_rect? dot, rect
          rect[0][0] <= dot[0] && dot[0] <= rect[1][0] &&
          rect[0][1] <= dot[1] && dot[1] <= rect[1][1]
        end
        
        def dot_in_circle? dot, circle
          (circle[0][0]-dot[0])**2 + (circle[0][1]-dot[1])**2 <= circle[1]**2
        end
      end
      
      attr_reader :target
      
      def initialize target, method_name, *options
        @target, @method_name, @options = target, method_name, options
      end
      
      # 衝突しているかどうかを判定する
      def collide? other
        other.collide_dispatch? self unless @dispatched
      end
      
      # 衝突しているかどうかを判定し、衝突していれば衝突処理を実行する
      def collide other
        return false unless collide? other
        call       other.target
        other.call @target
        return true
      end
      
      protected
      def call other
        @target.__send__ @method_name, other if @method_name
      end
      
      def collide_dispatch? other
        @dispatched = true
        self.collide? other
      ensure
        @dispatched = nil
      end
      
      def position
        [@target.x+@x, @target.y+@y]
      end
      
      # = Sprite::Collision::Builderクラス
      # スプライトの当たり判定を定義するクラス。
      class Builder
        def initialize target, name, collision, *options, &block
          @target, @name, @collision, @options = target, name, collision, options
          if block
            @method_name = "_starframe_sprite_collision__collision_#{@name}".to_sym
            @target.__send__ :define_method, @method_name, &block
          end
        end
        
        # 当たり判定を構築する。
        def build target
          @collision.new target, @method_name, *@options
        end
      end
    end
  end
end
